Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add specification for extending supported types of TKey in ditionaries. #32676

Merged
merged 4 commits into from
Sep 13, 2020

Conversation

jozkee
Copy link
Member

@jozkee jozkee commented Feb 21, 2020

Contributes to #30524

@jozkee jozkee added documentation Documentation bug or enhancement, does not impact product or test code area-System.Text.Json labels Feb 21, 2020
@jozkee jozkee added this to the 5.0 milestone Feb 21, 2020
* String
* UInt16
* UInt32
* UInt64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add char?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will add it.

I missed that one since the Utf8Formatter does not have a signature for it but the JsonSerializer supports it just fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding byte[] to this list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@am11 We can support it and do as we do for a byte[] value, which is write/read it as a Base64 string.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For floating point (Single and Double) does GetHashCode() and Equals() work as expected? Since a given Single value may be 1.23 for example but can be represented in more than one binary representation (i.e. the 4 bytes may be different). By default Equals() compare bytes which wouldn't work correctly in all cases @tannergooding

Copy link
Member

@tannergooding tannergooding Mar 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For float/double (and IEEE binary floating-point numbers in general), every bit representation for finite or infinite, non-zero floating-point values represents something unique.

The exceptions are:

  • +0.0 and -0.0
  • The many representations of NaN

Both ==/!= and Equals then perform standard equality comparisons for all other values (all non-zero finite values, and +/-infinity).
For ==/!= and Equals, +0 == -0

For ==/!=, any comparison where one operand is NaN returns false
For Equals, NaN is equal to any other NaN, regardless of underlying bit representation.

GetHashCode follows the same rule as Equals. That is +0 and -0 return the same hash code. All NaN return the same hash code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK thanks. So using Single\Double as a dictionary key makes sense. After looking at the binary representation for the non-exception cases I see the exponent is always normalized by selecting the smallest value that produces the representation (so binary representation of 1.23 == 123e-2 for example).

* Enum

# Notes
1. `DictionaryKeyPolicy` will apply to the resulting string of the non-string types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it? Does Newtonsoft have this behavior?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat yes, Newtonsoft does not have a DictionaryKeyPolicy per se, but it definitely calls the DictionaryKeyResolver after the key is converted to string.

https://dotnetfiddle.net/A3uJ0H


# Notes
1. `DictionaryKeyPolicy` will apply to the resulting string of the non-string types.
1. Should we provide a way to allow users to customize the `EnumKeyConverter` behavior, as it is done in `JsonStringEnumConverter`?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Should we provide a way to allow users to customize the `EnumKeyConverter` behavior, as it is done in `JsonStringEnumConverter`?
2. Should we provide a way to allow users to customize the `EnumKeyConverter` behavior, as it is done in `JsonStringEnumConverter`?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It really doesn't matter, when the markdown renders, it automatically enumerates the list.
See the rendered doc.

# Notes
1. `DictionaryKeyPolicy` will apply to the resulting string of the non-string types.
1. Should we provide a way to allow users to customize the `EnumKeyConverter` behavior, as it is done in `JsonStringEnumConverter`?
As of now `KeyConverter`s are meant to be internal types, to enable the previously described behavior we either pass the options through `JsonSerializerOptions` or through an attribute.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you imagine the work to make the type public should be scoped for 5.0? This initial support doesn't provide a way for users to customize (de)serialization of non-string dictionary keys. Is this acceptable for most users?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I have seen while writing the code, it does perfect sense to expose these types at some point, maybe you can make fit the effort needed for that into the 5.0 JSON roadmap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid scope creep and keep extension point + making it public out of the feature for now.

Is this acceptable for most users?

That should be the goal by the default/built-in behavior. Let's say 80% folks are successful with it.


# Goals
* 80%+ of dictionaries with non-string keys work out of the box, especially if they can round-trip.
* Remain high performance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some more detail around using string property names?

  • Use JSON property names for the key values. This produces more readable and smaller JSON and is consistent with Newtonsoft.Json.
    • However since property names must be a string, adds complexity since we now need a different mechanism to produce strings from non-string types.

* Users can hook up `TypeConverter`s for their own types.
* Not a high-performance alternative, involves unnecessary boxing.
* https://github.com/Jozkee/runtime/tree/TKeySupport_TypeConverter

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose an alternative is to not use string property names and instead use Name\Value combinations. Name\Value would likely be faster an just a few lines of code to enable since we don't need to add any new converter support.

@MaDeRkAn
Copy link

any progress ?

@jozkee
Copy link
Member Author

jozkee commented Jun 25, 2020

@MaDeRkAn See #38056

@ahsonkhan
Copy link
Member

Can we merge this spec?

Copy link
Contributor

@layomia layomia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging as the feature is checked in for 5.0 - #38056.

@layomia layomia merged commit c5a7d4d into dotnet:master Sep 13, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 10, 2020
@jozkee jozkee deleted the KeyConverterSpec branch March 24, 2021 19:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json documentation Documentation bug or enhancement, does not impact product or test code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants